
package com.zdkj.subway.rca.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zdkj.common.core.constant.SecurityConstants;
import com.zdkj.subway.rca.dto.SwCkClearSystemCompareExcelExportDTO;
import com.zdkj.subway.rca.dto.SwCkClearSystemCompareNoticeConfirmDTO;
import com.zdkj.subway.rca.entity.*;
import com.zdkj.subway.rca.feign.SubwaySupportService;
import com.zdkj.subway.rca.mapper.SwCkBankCashPaymentNoteMapper;
import com.zdkj.subway.rca.mapper.SwCkClearSystemCompareMapper;
import com.zdkj.subway.rca.mapper.SysDictCommonMapper;
import com.zdkj.subway.rca.service.SwCkClearSystemCompareService;
import com.zdkj.subway.rca.service.SwCkSystemClearingDiffReasonService;
import com.zdkj.subway.rca.util.LocalDateConverter;
import com.zdkj.subway.rca.util.LocalDateTimeConverter;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 系统清分数据对比
 *
 * @author cooze
 * @date 2020-10-31 21:40:25
 */
@Transactional(rollbackFor = Exception.class)
@Service
@Slf4j
public class SwCkClearSystemCompareServiceImpl extends ServiceImpl<SwCkClearSystemCompareMapper, SwCkClearSystemCompare> implements SwCkClearSystemCompareService {
    @Autowired
    private SysDictCommonMapper sysDictCommonMapper;
    @Autowired
    private SwCkSystemClearingDiffReasonService swCkSystemClearingDiffReasonService;
    @Autowired
    private SubwaySupportService subwaySupportService;

    @Autowired
    private SwCkBankCashPaymentNoteMapper swCkBankCashPaymentNoteMapper;

    @Override
    public IPage<SwCkClearSystemCompare> page(IPage<SwCkClearSystemCompare> page, Wrapper<SwCkClearSystemCompare> queryWrapper) {
        IPage<SwCkClearSystemCompare> pageResults = super.page(page, queryWrapper);
        if (CollectionUtil.isNotEmpty(pageResults.getRecords())) {
            pageResults.getRecords().forEach(rs -> rs.setDiffReason(baseMapper.selectDiffTypeById(rs.getId())));
        }
        return pageResults;
    }

    @Override
    public List<CodeName> queryDiffType() {
        return sysDictCommonMapper.selectAllDictKv("sw_ck_clear_system_compare_diff_type");
    }

    @Override
    public void batchConfirm(SwCkClearSystemCompareNoticeConfirmDTO dto) {
        baseMapper.batchUpdateConfirm(dto);
    }

    @Override
    public void batchNotice(SwCkClearSystemCompareNoticeConfirmDTO dto) {
        //查出有差异的数据
        List<SwCkClearSystemCompare> results = baseMapper.selectBatchIds(dto.getIdList());
        if (CollectionUtil.isEmpty(results)) {
            log.warn("通知失败，通知目标数据未找到");
            return;
        }
        //生成差异数据
        RetDiff retDiff = createDiffData(results, dto);
        //差异数据入库
        if (Objects.nonNull(retDiff) && CollectionUtil.isNotEmpty(retDiff.getResults())) {
            swCkSystemClearingDiffReasonService.saveBatch(retDiff.getResults());
        }
        //修改通知状态
        baseMapper.batchUpdateNotice(dto);
        //通知
        TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
            @Override
            public void afterCommit() {
                if (Objects.nonNull(retDiff) && CollectionUtil.isNotEmpty(retDiff.getSwMessages())) {
                    for (SwMessage message : retDiff.getSwMessages())
                        subwaySupportService.saveInner(message, SecurityConstants.FROM_IN);
                }
            }
        });
    }

    @Override
    public void excelExport(SwCkClearSystemCompareExcelExportDTO dto, HttpServletResponse response) {

        //获取模板excel文件流
        try (InputStream excelTemplate = new PathMatchingResourcePatternResolver().getResource("classpath:/static/excel/template/export/SwCkClearSystemCompare.xlsx").getInputStream()) {
            response.reset(); // 非常重要
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
            response.setHeader("Content-disposition", exportFileName());
            ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).registerConverter(new LocalDateTimeConverter()).registerConverter(new LocalDateConverter()).withTemplate(excelTemplate).build();
            //填充数据
            List<SwCkClearSystemCompare> results = queryExportDataResult(dto);
            excelWriter.fill(results, EasyExcel.writerSheet(excelSheetName()).build());
            excelWriter.finish();
        } catch (Exception e) {
            log.error("SwCkReportReviewServiceImpl export error.", e);
        }
    }

    private String excelSheetName() {
        return "系统清分数据对比";
    }

    private List<SwCkClearSystemCompare> queryExportDataResult(SwCkClearSystemCompareExcelExportDTO dto) {
        boolean isContainMainReport = StringUtils.isNotEmpty(dto.getStartDate()) && StringUtils.isNotEmpty(dto.getEndDate());
        SwCkClearSystemCompare cp = new SwCkClearSystemCompare();
        if (StringUtils.isNotEmpty(dto.getLineCode())) {
            cp.setLineCode(dto.getLineCode());
        }
        if (StringUtils.isNotEmpty(dto.getConfirmStatus())) {
            cp.setConfirmStatus(dto.getConfirmStatus());
        }
        if (StringUtils.isNotEmpty(dto.getNoticeStatus())) {
            cp.setNoticeStatus(dto.getNoticeStatus());
        }
        List<SwCkClearSystemCompare> list = baseMapper.selectList(
                Wrappers.query(cp).lambda()
                        .between(isContainMainReport, SwCkClearSystemCompare::getTradeDate, dto.getStartDate(), dto.getEndDate())
        );
        if (CollectionUtil.isEmpty(list)) {
            return list;
        }
        Map<String, String> map = new HashMap<>();
        List<CodeName> subwayLine = swCkBankCashPaymentNoteMapper.listAllSubWayLine(null);

        if (CollectionUtil.isNotEmpty(subwayLine)) {
            subwayLine.forEach(codeName -> map.put(codeName.getCode(), codeName.getName()));
        }

        for (SwCkClearSystemCompare compare : list) {
            compare.setDiffReason(baseMapper.selectDiffTypeById(compare.getId()));
            compare.setLineCodeName(map.get(compare.getLineCode()));
        }
        return list;
    }

    private String exportFileName() throws UnsupportedEncodingException {
        return String.format("attachment;filename=%s.xlsx", (URLEncoder.encode(excelSheetName(), "UTF-8") + System.currentTimeMillis()));
    }

    private RetDiff createDiffData(List<SwCkClearSystemCompare> compares, SwCkClearSystemCompareNoticeConfirmDTO dto) {
        List<SwCkSystemClearingDiffReason> results = new LinkedList<>();
        List<SwMessage> swMessages = new LinkedList<>();
        Map<String, String> diffMap = diffMap();
        if (CollectionUtil.isEmpty(diffMap)) {
            log.warn("差异码表数据不存在");
            return null;
        }
        for (SwCkClearSystemCompare compare : compares) {
            //二维码电子票合计金额(分) 差异
            if (existDiff(compare.getDiffQrCodeTicketAmount(), (compare.getQrCodeTicketAmount().add(compare.getCompareQrCodeTicketAmount())))) {
                SwCkSystemClearingDiffReason diffReason = new SwCkSystemClearingDiffReason();
                diffReason.setCreatorId(dto.getCreatorId());
                diffReason.setCreatorName(dto.getCreatorName());
                diffReason.setCreateTime(LocalDateTime.now());
                diffReason.setDiffReasonTime(LocalDateTime.now());
                diffReason.setRelationid(compare.getId());
                diffReason.setIsReplay("0");
                diffReason.setSendStatus("0");
                diffReason.setDiffType("2");
                diffReason.setDiffReason(diffMap.get("2"));
                //通知信息
                SwMessage swMessage = new SwMessage();
                swMessage.setTitle("系统清分数据差异");
                swMessage.setMsgType("0");
                swMessage.setSendDeptCode(StringUtils.isEmpty(dto.getLineCode()) ? compare.getLineCode() : dto.getLineCode());
                swMessage.setDeptId(dto.getDeptId());
                swMessage.setContent(diffMap.get("2"));
                results.add(diffReason);
                swMessages.add(swMessage);


            }
            //交通一卡通合计金额(分) 差异
            if (existDiff(compare.getDiffTrafficCardAmount(), compare.getTrafficCardAmount().add(compare.getCompareTrafficCardAmount()))) {
                SwCkSystemClearingDiffReason diffReason = new SwCkSystemClearingDiffReason();
                diffReason.setCreatorId(dto.getCreatorId());
                diffReason.setCreatorName(dto.getCreatorName());
                diffReason.setCreateTime(LocalDateTime.now());
                diffReason.setDiffReasonTime(LocalDateTime.now());
                diffReason.setRelationid(compare.getId());
                diffReason.setIsReplay("0");
                diffReason.setSendStatus("0");
                diffReason.setDiffType("3");
                diffReason.setDiffReason(diffMap.get("3"));
                //通知信息
                SwMessage swMessage = new SwMessage();
                swMessage.setTitle("系统清分数据差异");
                swMessage.setMsgType("0");
                swMessage.setSendDeptCode(StringUtils.isEmpty(dto.getLineCode()) ? compare.getLineCode() : dto.getLineCode());
                swMessage.setDeptId(dto.getDeptId());
                swMessage.setContent(diffMap.get("3"));
                results.add(diffReason);
                swMessages.add(swMessage);

            }
            //长安通合计金额(分) 差异
            if (existDiff(compare.getDiffChanganTongCashAmount(), compare.getChanganTongCashAmount().add(compare.getCompareChanganTongCashAmount()))) {
                SwCkSystemClearingDiffReason diffReason = new SwCkSystemClearingDiffReason();
                diffReason.setCreatorId(dto.getCreatorId());
                diffReason.setCreatorName(dto.getCreatorName());
                diffReason.setCreateTime(LocalDateTime.now());
                diffReason.setDiffReasonTime(LocalDateTime.now());
                diffReason.setRelationid(compare.getId());
                diffReason.setIsReplay("0");
                diffReason.setSendStatus("0");
                diffReason.setDiffType("4");
                diffReason.setDiffReason(diffMap.get("4"));
                //通知信息
                SwMessage swMessage = new SwMessage();
                swMessage.setTitle("系统清分数据差异");
                swMessage.setMsgType("0");
                swMessage.setSendDeptCode(StringUtils.isEmpty(dto.getLineCode()) ? compare.getLineCode() : dto.getLineCode());
                swMessage.setDeptId(dto.getDeptId());
                swMessage.setContent(diffMap.get("4"));
                results.add(diffReason);
                swMessages.add(swMessage);

            }
            //人脸电子票合计金额(分) 导入（对比）、差异
            if (existDiff(compare.getDiffFaceTicketAmount(), compare.getFaceTicketAmount().add(compare.getCompareFaceTicketAmount()))) {
                SwCkSystemClearingDiffReason diffReason = new SwCkSystemClearingDiffReason();
                diffReason.setCreatorId(dto.getCreatorId());
                diffReason.setCreatorName(dto.getCreatorName());
                diffReason.setCreateTime(LocalDateTime.now());
                diffReason.setDiffReasonTime(LocalDateTime.now());
                diffReason.setRelationid(compare.getId());
                diffReason.setIsReplay("0");
                diffReason.setSendStatus("0");
                diffReason.setDiffType("5");
                diffReason.setDiffReason(diffMap.get("5"));
                //通知信息
                SwMessage swMessage = new SwMessage();
                swMessage.setTitle("系统清分数据差异");
                swMessage.setMsgType("0");
                swMessage.setSendDeptCode(StringUtils.isEmpty(dto.getLineCode()) ? compare.getLineCode() : dto.getLineCode());
                swMessage.setDeptId(dto.getDeptId());
                swMessage.setContent(diffMap.get("5"));
                results.add(diffReason);
                swMessages.add(swMessage);

            }
            //单程票清分 差异
            if (existDiff(compare.getDiffOneWayTickets(), compare.getOneWayTickets().add(compare.getCompareOneWayTickets()))) {
                SwCkSystemClearingDiffReason diffReason = new SwCkSystemClearingDiffReason();
                diffReason.setCreatorId(dto.getCreatorId());
                diffReason.setCreatorName(dto.getCreatorName());
                diffReason.setCreateTime(LocalDateTime.now());
                diffReason.setDiffReasonTime(LocalDateTime.now());
                diffReason.setRelationid(compare.getId());
                diffReason.setIsReplay("0");
                diffReason.setSendStatus("0");
                diffReason.setDiffType("1");
                diffReason.setDiffReason(diffMap.get("1"));
                results.add(diffReason);
                //通知信息
                SwMessage swMessage = new SwMessage();
                swMessage.setTitle("系统清分数据差异");
                swMessage.setMsgType("0");
                swMessage.setSendDeptCode(StringUtils.isEmpty(dto.getLineCode()) ? compare.getLineCode() : dto.getLineCode());
                swMessage.setDeptId(dto.getDeptId());
                swMessage.setContent(diffMap.get("1"));
                swMessages.add(swMessage);

            }

        }
        RetDiff retDiff = new RetDiff();
        retDiff.setResults(results);
        retDiff.setSwMessages(swMessages);
        return retDiff;
    }


    private boolean existDiff(BigDecimal diff, BigDecimal sum) {
        return Objects.nonNull(diff) && (diff.subtract(sum).compareTo(BigDecimal.ZERO) > 0);
    }


    private Map<String, String> diffMap() {
        Map<String, String> diffMap = new HashMap<>();
        List<CodeName> list = queryDiffType();
        if (CollectionUtil.isEmpty(list)) {
            return diffMap;
        }
        list.forEach(codeName -> diffMap.put(codeName.getCode(), codeName.getName()));
        return diffMap;
    }


    @Data
    private class RetDiff {
        List<SwCkSystemClearingDiffReason> results;
        List<SwMessage> swMessages;

    }
}
